# management/tasks.py
from celery import shared_task, current_app
from django.contrib.auth.models import User
from django.utils import timezone
from datetime import timedelta
from management.initialization import DataInitializer
from management.updater import DataUpdater
from memento.models import UserStateMemento
from recommendation_pool.models import UserUndoPool
import time
from datetime import datetime
import logging

from utils.export_user_data_to_md import export_user_data_to_md

logger = logging.getLogger('management')


class UserDataTasks:

    @staticmethod
    @shared_task
    def async_initialize_user_data(user_id):

        logger.info(f"==Initialize user data task begin for user_id{user_id}==")
        user = None  # 预先初始化为 None
        try:
            user = User.objects.get(id=user_id)

            # 检查 is_computing 字段，如果为 1 则结束任务并提示
            if user.usercontrol.is_computing:
                print(f"User with id {user_id} is already computing.")
                return

            # 设置 is_computing 为 1 表示任务开始
            user.usercontrol.is_computing = True
            user.usercontrol.save()

            # 执行数据初始化
            DataInitializer.initialize_user_data(user)

        except User.DoesNotExist:
            print(f"User with id {user_id} does not exist.")
            logger.error(f"User with id {user_id} does not exist.")


        except Exception as e:
            print(f"An error occurred: {str(e)}")
            logger.error(f"An error occurred when Initialize {str(e)}")

        finally:
            # 无论是否发生异常，确保 is_computing 恢复为 0
            logger.info(f"==Initialize user data task end for user_id{user_id}==")
            if user and hasattr(user, 'usercontrol'):   # 确保用户对象 user存在 且 user 上确实存在 usercontrol 属性
                user.usercontrol.is_computing = False
                user.usercontrol.save()

    @staticmethod
    @shared_task
    def async_create_memento(user_id):
        UserStateMemento.create_memento(user_id)

    @staticmethod
    @shared_task(bind=True)
    def async_process_user_data_cycle(self, user_id):
        logger.info(f"Begin ======async_process_user_data_cycle for user_id {user_id} begin at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}======")
        user = None  # 预先初始化为 None
        try:
            # 获取用户对象并检查 usercontrol 是否存在
            user = User.objects.get(pk=user_id)
            if not hasattr(user, 'usercontrol'):
                print(f"UserControl instance for user {user_id} does not exist.")
                logger.info(f"UserControl instance for user {user_id} does not exist.")
                return

            user_control = user.usercontrol

            if user_control.task_count == 0:
                print("UserControl.task_count is 0. So cannot process data. Task aborted.")
                logger.info(f"user_id{user_id} UserControl.task_count is 0. So cannot process data. Task aborted.")
                return

            # 检查当前时间与 next_task_time 的差距是否过大
            if user_control.next_task_time:

                current_time = timezone.now()
                time_difference = abs((current_time - user_control.next_task_time).total_seconds())
                # 设置一个阈值,10min = 600s
                allowed_time_difference = 600  # 秒
                if time_difference > allowed_time_difference:
                    print("Task execution time is off by {time_difference} seconds. Task aborted.")
                    logger.info(f"user_id{user_id} Task execution time is off by {time_difference} seconds. Task aborted.")
                    return
            else:
                print("No scheduled task at this time.")
                logger.info(f"user_id{user_id} No scheduled task at this time.")
                return

            # 判断 is_computing 是否已被设置为 True，若是则提示并结束任务
            if user_control.is_computing:
                print(f"User {user_id} is already processing data. Task aborted.")
                logger.info(f"User {user_id} is already processing data. Task aborted.")
                return

            # 检查用户上次活动时间是否在30分钟内
            if user_control.last_activity and timezone.now() - user_control.last_activity <= timedelta(minutes=30):
                # 若最近活跃，递交一个4小时后的递归任务
                UserDataTasks.submit_or_replace_task(
                    user_id, UserDataTasks.async_process_user_data_cycle, countdown=14400
                )
                user_control.next_task_time = timezone.now() + timedelta(hours=4)
                user_control.save()
                logger.info(f"user_id{user_id} User is active now, process it 4h later")

                return

            # 将 is_computing 设置为 True 表示任务正在执行
            user_control.is_computing = True
            user_control.save()

            # 恢复原有状态
            UserStateMemento.restore_memento(user_id)

            # 在原有状态基础上更新
            DataUpdater.update_data_fetch(user)

            # 创建 memento
            UserStateMemento.create_memento(user_id)

            # 执行数据清洗和恢复操作
            UserUndoPool.remove_if_solved(user_id)
            UserUndoPool.move_expired_to_recommendation_pool(user_id)
            logger.info(f"user_id{user_id} task process successfully")
            # 根据用户上次活跃时间和任务数量决定任务的调度或递减 task_count
            if user_control.last_activity and timezone.now() - user_control.last_activity <= timedelta(days=3):
                # 如果最近活跃且任务数为1，插入6小时后的任务（保持 task_count 不变）
                if user_control.task_count == 1:
                    UserDataTasks.submit_or_replace_task(
                        user_id, UserDataTasks.async_process_user_data_cycle, countdown=21600
                    )
                    user_control.next_task_time = timezone.now() + timedelta(hours=6)
                    logger.info(f"user_id{user_id} this task Submit a 6h task")
            else:
                # 如果超过三天不活跃且任务数大于等于1，递减 task_count
                if user_control.task_count >= 1:
                    user_control.task_count -= 1
                    user_control.next_task_time = None
                    logger.info(f"user_id{user_id} No task submit because user is no more active")

            # 将 is_computing 重置为 False 以表示任务完成
            user_control.is_computing = False
            user_control.save()
            # 将用户现在的状态记录为markdown文件
            # export_user_data_to_md(user_id)
            logger.info(f"user_id{user_id} write down to markdown")
        except User.DoesNotExist:
            print(f"User with id {user_id} does not exist.")
            logger.info(f"User with id {user_id} does not exist.")
        finally:
            # 确保在任何异常情况下都将 is_computing 重置为 False
            logger.info(f"End ======async_process_user_data_cycle for user_id {user_id} end at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}======")
            if user and hasattr(user, 'usercontrol') and user.usercontrol.is_computing:
                user.usercontrol.is_computing = False
                user.usercontrol.save()

    # # 使用示例
    # UserDataTasks.submit_or_replace_task(user.id, UserDataTasks.async_initialize_user_data)
    # UserDataTasks.submit_or_replace_task(user.id, UserDataTasks.async_create_memento)
    # UserDataTasks.submit_or_replace_task(user.id, UserDataTasks.async_process_user_data_cycle, countdown=21600)
    # 6小时后执行
    # @staticmethod
    # def submit_or_replace_task(user_id, task_func, countdown=None):
    #     task_id = f"{task_func.__name__}_{user_id}"
    #     try:
    #         # 尝试撤销现有任务
    #         revoked = current_app.control.revoke(task_id, terminate=True)
    #         if revoked:  # 如果成功撤销
    #             print("Existing task revoked")
    #     except Exception as e:
    #         print(f"Error revoking task: {str(e)}")
    #
    #     # 提交新任务
    #     if countdown:
    #         task_func.apply_async((user_id,), countdown=countdown, task_id=task_id)
    #     else:
    #         task_func.apply_async((user_id,), task_id=task_id)

    @staticmethod
    def submit_or_replace_task(user_id, task_func, countdown=None, *args, **kwargs):
        task_name = task_func.__name__
        timestamp = int(time.time())  # 获取当前时间戳
        task_id = f"{task_name}_{user_id}_{timestamp}"  # 添加时间戳到任务ID
        # revoke待实现

        # 提交新任务
        if countdown:
            task_func.apply_async((user_id,), countdown=countdown, task_id=task_id, **kwargs)
        else:
            task_func.apply_async((user_id,), task_id=task_id, **kwargs)

        # 提交新任务
